
#include "stm8s.h"
#include "jxos_public.h"

swtime_type spi_swt;
swtime_type buzzer_swt;

void uart_send_byte(uint8_t c);
void move_to_level(uint8_t level, uint8_t tick_time);

enum KEY
{
	KEY_ON_OFF = 0,
	KEY_SCENES_1,
	KEY_SCENES_2,
	KEY_SCENES_3,
	KEY_SCENES_4,
	KEY_LEVEL_UP,
	KEY_LEVEL_DOWN,
	KEY_GROUP_1,
	KEY_GROUP_2,
	KEY_GROUP_3,
	KEY_GROUP_4,
	KEY_GROUP_5,
	KEY_GROUP_6
};

static uint8_t button_list[] = {
	0xff,			//NC
	0xff,			//NC
	KEY_GROUP_2,	
	KEY_GROUP_4,
	KEY_GROUP_6,
	KEY_GROUP_1,
	KEY_GROUP_3,
	KEY_GROUP_5,
	KEY_LEVEL_DOWN,
	KEY_LEVEL_UP,
	KEY_SCENES_2,
	KEY_SCENES_4,
	KEY_SCENES_1,
	KEY_SCENES_3,
	KEY_ON_OFF,
	KEY_ON_OFF
};

static void send_button_code(uint8_t press, uint8_t button_num)
{
	press <<= 7;
	press += button_list[button_num];
	uart_send_byte(press);
}


static uint8_t spi_task_transmit(uint8_t send_data)
{
	uint8_t RX = 0;
  /*!< Wait until the transmit buffer is empty */
  while(SPI_GetFlagStatus(SPI_FLAG_TXE) == RESET)
  {
  }

  /*!< Send the byte */
  SPI_SendData(send_data);

  /*!< Wait to receive a byte*/
  while(SPI_GetFlagStatus(SPI_FLAG_RXNE) == RESET)
  {
  }

  /*!< Return the byte read from the SPI bus */
	return SPI_ReceiveData();
}

static void buzzer_on_with_auto_off(void)
{
	GPIO_WriteLow(GPIOB, (GPIO_Pin_TypeDef)GPIO_PIN_6);
	sys_svc_software_timer_restart(buzzer_swt);
}


static void button_press_handler(uint8_t button_num)
{
	buzzer_on_with_auto_off();
//	move_to_level(255, 1);
	send_button_code(1, button_num);
}

static void button_relese_handler(uint8_t button_num)
{
	send_button_code(0, button_num);
}

static uint8_t check_bit(uint8_t data1, uint8_t data2)
{
	data1 = data1^data2;
	data2 = 0;
	while(1){
		if(data1&(1<<data2)){
			break;
		}
		data2++;
		if(data2 > 7){
			break;
		}
	}
	return data2;
}

static uint8_t button_state_last[3] = {0};
static void button_scan(void)
{
	uint8_t button_num;
	uint8_t byte_num;
	uint8_t bit_num;
	uint8_t read_data;
	GPIO_WriteLow(GPIOE, (GPIO_Pin_TypeDef)GPIO_PIN_5);
	read_data = spi_task_transmit(0xff);
	GPIO_WriteHigh(GPIOE, (GPIO_Pin_TypeDef)GPIO_PIN_5);
	
	byte_num = (read_data&0x03);
	if(byte_num <= 2){
		if(button_state_last[byte_num] != read_data){
			bit_num = check_bit(button_state_last[byte_num], read_data);
			button_state_last[byte_num] = read_data;
			if((bit_num >= 2)&&(bit_num < 8)){
				button_num = bit_num + byte_num*6 - 2;
				bit_num = read_data&(1<<bit_num);
				if(bit_num) //press
				{
					button_press_handler(button_num);
				}
				else{
					button_relese_handler(button_num);
				}
			}
		}
	}
}

static void spi_task(uint8_t task_id, void * parameter)
{
	if(1 == sys_svc_software_timer_check_overtime(spi_swt)){
		button_scan();
	}
	if(1 == sys_svc_software_timer_check_overtime(buzzer_swt)){
		sys_svc_software_timer_stop(buzzer_swt);
		GPIO_WriteHigh(GPIOB, (GPIO_Pin_TypeDef)GPIO_PIN_6);
	}
}

void spi_task_init(void)
{
	//buzzer pin
	GPIO_Init(GPIOB, (GPIO_Pin_TypeDef)GPIO_PIN_6, GPIO_MODE_OUT_PP_HIGH_SLOW);
	GPIO_WriteHigh(GPIOB, (GPIO_Pin_TypeDef)GPIO_PIN_6);
	
	//spi pin: PE5->SCS PC5->SCK PC6->SDI PC7->SDO
	GPIO_Init(GPIOC, (GPIO_Pin_TypeDef)(GPIO_PIN_5 | GPIO_PIN_6), GPIO_MODE_OUT_PP_HIGH_FAST);
	GPIO_Init(GPIOC, (GPIO_Pin_TypeDef)GPIO_PIN_7, GPIO_MODE_IN_PU_NO_IT);
	GPIO_Init(GPIOE, (GPIO_Pin_TypeDef)GPIO_PIN_5, GPIO_MODE_OUT_PP_HIGH_FAST);

	/* SPI configuration */
	SPI_DeInit();
	/* Initialize SPI in Slave mode  */
	SPI_Init(SPI_FIRSTBIT_MSB, SPI_BAUDRATEPRESCALER_256, SPI_MODE_MASTER, SPI_CLOCKPOLARITY_HIGH,
		   SPI_CLOCKPHASE_2EDGE, SPI_DATADIRECTION_2LINES_FULLDUPLEX, SPI_NSS_SOFT,(uint8_t)0x07);
	/* Enable the SPI*/
	SPI_Cmd(ENABLE);
	
	jxos_task_create(spi_task, "spi", 0);
	spi_swt = sys_svc_software_timer_new();
	sys_svc_software_timer_set_time(spi_swt, 5);
	sys_svc_software_timer_start(spi_swt);
	
	buzzer_swt = sys_svc_software_timer_new();
	sys_svc_software_timer_set_time(buzzer_swt, 25);
	
	buzzer_on_with_auto_off();
}

/**********************************************************/
//WTC6316BSI

/**
  * @brief  Inserts a delay time.
  *         The delay function implemented in this driver is not a precise one,
  *         however it allows the insertion of 1ms delay when Fcpu is 16Mhz if
  *         the passed parameter is 0x4000.
  *         Any change in system clock frequency will impact this delay duration.
  *
  *         User is given the possibility to develop a customized and accurate
  *         delay function by the mean of timers for example.
  *         Uncommenting " #define USE_Delay" line in the stm8s_eval_lcd.h file
  *         will allow the consideration of the new function by this driver.
  *
  * @param  nCount: specifies the _delay_ time length.
  * @retval None
  */
//static void delay(__IO uint32_t nCount)
//{
//  /* Decrement nCount value */
//  while (nCount != 0)
//  {
//    nCount--;
//  }
//}

void  WTC6316BSI_set_sensibility(uint8_t sensibility)
{
	if(sensibility <= 15){
		spi_task_transmit(sensibility);
	}
}

/*********************************************************
//shift_mod:
BIT:	7		6		5		4		3		2		1	0
byte0	SW5		SW4		SW3		SW2		SW1		SW0		0	0
byte1	SW11	SW10	SW9		SW8		SW7		SW6		0	1
byte2	0		0		SW15	SW14	SW13	SW12	1	0
SWx: 0->free;	1->press
*********************************************************/
//void WTC6316BSI_shift_mod_read(void)
//{
//	uint8_t mark = 0;
// uint8_t buff = 0;
//	GPIO_WriteLow(GPIOE, (GPIO_Pin_TypeDef)GPIO_PIN_5);
//	delay(0x4000); /* 1ms _delay_ using Fcpu = 16Mhz*/
//	while(1){
//		buff = spi_task_transmit(0xaa);
//		read_data[(buff&0x03)] = buff;
//		mark += 1<<(buff&0x03);
//		if(mark == 0x07){
//			break;
//		}
//	}
//	GPIO_WriteHigh(GPIOE, (GPIO_Pin_TypeDef)GPIO_PIN_5);

//	delay(0x4000); /* 1ms _delay_ using Fcpu = 16Mhz*/
//}

/*********************************************************
//single_mod:
data: 	0->SW0 press;  1->SW1 press; ... 15->SW15 press; 
		0xff->all free
*********************************************************/
//uint8_t WTC6316BSI_single_mod_read(void)
//{
//	return spi_task_transmit(0xff);
//}



